// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/accessible_pane_view.h"

#include "base/macros.h"
#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"

#if defined(OS_MACOSX)
#include "ui/base/test/scoped_fake_nswindow_focus.h"
#endif

namespace views {

// TODO(alicet): bring pane rotation into views and add tests.
//               See browser_view.cc for details.

typedef ViewsTestBase AccessiblePaneViewTest;

class TestBarView : public AccessiblePaneView,
                    public ButtonListener {
public:
    TestBarView();
    ~TestBarView() override;

    void ButtonPressed(Button* sender, const ui::Event& event) override;
    LabelButton* child_button() const { return child_button_.get(); }
    LabelButton* second_child_button() const
    {
        return second_child_button_.get();
    }
    LabelButton* third_child_button() const { return third_child_button_.get(); }
    LabelButton* not_child_button() const { return not_child_button_.get(); }

    View* GetDefaultFocusableChild() override;

private:
    void Init();

    scoped_ptr<LabelButton> child_button_;
    scoped_ptr<LabelButton> second_child_button_;
    scoped_ptr<LabelButton> third_child_button_;
    scoped_ptr<LabelButton> not_child_button_;

    DISALLOW_COPY_AND_ASSIGN(TestBarView);
};

TestBarView::TestBarView()
{
    Init();
    set_allow_deactivate_on_esc(true);
}

TestBarView::~TestBarView() { }

void TestBarView::ButtonPressed(Button* sender, const ui::Event& event)
{
}

void TestBarView::Init()
{
    SetLayoutManager(new FillLayout());
    base::string16 label;
    child_button_.reset(new LabelButton(this, label));
    AddChildView(child_button_.get());
    second_child_button_.reset(new LabelButton(this, label));
    AddChildView(second_child_button_.get());
    third_child_button_.reset(new LabelButton(this, label));
    AddChildView(third_child_button_.get());
    not_child_button_.reset(new LabelButton(this, label));
}

View* TestBarView::GetDefaultFocusableChild()
{
    return child_button_.get();
}

TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus)
{
    TestBarView* test_view = new TestBarView();
    scoped_ptr<Widget> widget(new Widget());
    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    params.bounds = gfx::Rect(50, 50, 650, 650);
    widget->Init(params);
    View* root = widget->GetRootView();
    root->AddChildView(test_view);
    widget->Show();
    widget->Activate();

    // Set pane focus succeeds, focus on child.
    EXPECT_TRUE(test_view->SetPaneFocusAndFocusDefault());
    EXPECT_EQ(test_view, test_view->GetPaneFocusTraversable());
    EXPECT_EQ(test_view->child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());

    // Set focus on non child view, focus failed, stays on pane.
    EXPECT_TRUE(test_view->SetPaneFocus(test_view->not_child_button()));
    EXPECT_FALSE(test_view->not_child_button() == test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    EXPECT_EQ(test_view->child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    widget->CloseNow();
    widget.reset();
}

TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore)
{
#if defined(OS_MACOSX)
    // On Aura platforms, this test creates Ash windows and only interacts with
    // the Ash window manager. On Mac, it creates native windows, but since unit
    // tests cannot gain key status, fake it out here.
    ui::test::ScopedFakeNSWindowFocus fake_focus;
#endif

    View* test_view_main = new View();
    scoped_ptr<Widget> widget_main(new Widget());
    Widget::InitParams params_main = CreateParams(Widget::InitParams::TYPE_POPUP);
    params_main.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    // By default, TYPE_POPUP is not activatable.
    params_main.activatable = Widget::InitParams::ACTIVATABLE_YES;
    params_main.bounds = gfx::Rect(0, 0, 20, 20);
    widget_main->Init(params_main);
    View* root_main = widget_main->GetRootView();
    root_main->AddChildView(test_view_main);
    widget_main->Activate();
    test_view_main->GetFocusManager()->SetFocusedView(test_view_main);
    EXPECT_TRUE(widget_main->IsActive());
    EXPECT_TRUE(test_view_main->HasFocus());

    TestBarView* test_view_bar = new TestBarView();
    scoped_ptr<Widget> widget_bar(new Widget());
    Widget::InitParams params_bar = CreateParams(Widget::InitParams::TYPE_POPUP);
    params_bar.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    params_bar.activatable = Widget::InitParams::ACTIVATABLE_YES;
    params_bar.bounds = gfx::Rect(50, 50, 650, 650);
    widget_bar->Init(params_bar);
    View* root_bar = widget_bar->GetRootView();
    root_bar->AddChildView(test_view_bar);
    widget_bar->Show();
    widget_bar->Activate();

    // Set pane focus succeeds, focus on child.
    EXPECT_TRUE(test_view_bar->SetPaneFocusAndFocusDefault());
    EXPECT_FALSE(test_view_main->HasFocus());
    EXPECT_FALSE(widget_main->IsActive());
    EXPECT_EQ(test_view_bar, test_view_bar->GetPaneFocusTraversable());
    EXPECT_EQ(test_view_bar->child_button(),
        test_view_bar->GetWidget()->GetFocusManager()->GetFocusedView());

    // Deactivate() is only reliable on Ash. On Windows it uses ::GetNextWindow()
    // to simply activate another window, and which one is not predictable. On
    // Mac, Deactivate() is not implemented. Note that TestBarView calls
    // set_allow_deactivate_on_esc(true), which is only otherwise used in Ash.
#if !defined(OS_MACOSX) || defined(USE_ASH)
    // Esc should deactivate the widget.
    test_view_bar->AcceleratorPressed(test_view_bar->escape_key());
    EXPECT_TRUE(widget_main->IsActive());
    EXPECT_FALSE(widget_bar->IsActive());
#endif

    widget_bar->CloseNow();
    widget_bar.reset();

    widget_main->CloseNow();
    widget_main.reset();
}

TEST_F(AccessiblePaneViewTest, TwoSetPaneFocus)
{
    TestBarView* test_view = new TestBarView();
    TestBarView* test_view_2 = new TestBarView();
    scoped_ptr<Widget> widget(new Widget());
    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    params.bounds = gfx::Rect(50, 50, 650, 650);
    widget->Init(params);
    View* root = widget->GetRootView();
    root->AddChildView(test_view);
    root->AddChildView(test_view_2);
    widget->Show();
    widget->Activate();

    // Set pane focus succeeds, focus on child.
    EXPECT_TRUE(test_view->SetPaneFocusAndFocusDefault());
    EXPECT_EQ(test_view, test_view->GetPaneFocusTraversable());
    EXPECT_EQ(test_view->child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());

    // Set focus on another test_view, focus move to that pane.
    EXPECT_TRUE(test_view_2->SetPaneFocus(test_view_2->second_child_button()));
    EXPECT_FALSE(test_view->child_button() == test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    EXPECT_EQ(test_view_2->second_child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    widget->CloseNow();
    widget.reset();
}

TEST_F(AccessiblePaneViewTest, PaneFocusTraversal)
{
    TestBarView* test_view = new TestBarView();
    TestBarView* original_test_view = new TestBarView();
    scoped_ptr<Widget> widget(new Widget());
    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    params.bounds = gfx::Rect(50, 50, 650, 650);
    widget->Init(params);
    View* root = widget->GetRootView();
    root->AddChildView(original_test_view);
    root->AddChildView(test_view);
    widget->Show();
    widget->Activate();

    // Set pane focus on first view.
    EXPECT_TRUE(original_test_view->SetPaneFocus(
        original_test_view->third_child_button()));

    // Test travesal in second view.
    // Set pane focus on second child.
    EXPECT_TRUE(test_view->SetPaneFocus(test_view->second_child_button()));
    // home
    test_view->AcceleratorPressed(test_view->home_key());
    EXPECT_EQ(test_view->child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    // end
    test_view->AcceleratorPressed(test_view->end_key());
    EXPECT_EQ(test_view->third_child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    // left
    test_view->AcceleratorPressed(test_view->left_key());
    EXPECT_EQ(test_view->second_child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    // right, right
    test_view->AcceleratorPressed(test_view->right_key());
    test_view->AcceleratorPressed(test_view->right_key());
    EXPECT_EQ(test_view->child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());

    // ESC
    test_view->AcceleratorPressed(test_view->escape_key());
    EXPECT_EQ(original_test_view->third_child_button(),
        test_view->GetWidget()->GetFocusManager()->GetFocusedView());
    widget->CloseNow();
    widget.reset();
}
} // namespace views
